package com.morristaedt.mirror.modules.voice;

import android.content.Context;
import android.content.res.AssetManager;
import android.text.TextUtils;
import android.util.Log;

import com.iflytek.aiui.AIUIAgent;
import com.iflytek.aiui.AIUIConstant;
import com.iflytek.aiui.AIUIEvent;
import com.iflytek.aiui.AIUIListener;
import com.iflytek.aiui.AIUIMessage;
import com.morristaedt.mirror.MirrorApplication;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 智能语音对话模块
 */
public class AIUIVoice {


    private static final String TAG = "AIUIVoice";
    private AIUIAgent mAIUIAgent;
    private Context context;
    private int mCurrentState = AIUIConstant.STATE_IDLE;
    private String mSyncSid = "";
    private long mAudioStart = System.currentTimeMillis();
    private MessageHandler messageHandler;
    public AIUIVoice(Context context, OnVoiceAIListener voiceAIListener) {
        this.context = context;
        this.voiceAIListener = voiceAIListener;
        mAIUIAgent = AIUIAgent.createAgent(context, getAIUIParams(), mAIUIListener);
        messageHandler = new MessageHandler();
    }

    public MessageHandler getMessageHandler(){
        return messageHandler;
    }



    public void wakeUp() {
        // 默认为oneshot模式，即一次唤醒后就进入休眠。可以修改aiui_phone.cfg中speech参数的interact_mode为continuous以支持持续交互
        //if (AIUIConstant.STATE_WORKING != mAIUIState)
        AIUIMessage wakeupMsg = new AIUIMessage(AIUIConstant.CMD_WAKEUP, 0, 0, "", null);
        sendMessage(wakeupMsg);
    }

    public void sleep(){
        AIUIMessage reset_wakeupMsg = new AIUIMessage(AIUIConstant.CMD_RESET_WAKEUP, 0, 0, "", null);
        sendMessage(reset_wakeupMsg);
    }


    public void destroyAgent() {
        if (null != mAIUIAgent) {
            Log.i(TAG, "destroy aiui agent");

            mAIUIAgent.destroy();
            mAIUIAgent = null;
            showTip("AIUIAgent已销毁");
        } else {
            showTip("AIUIAgent为空");
        }
    }



    public void stopRecordAudio() {
        sendMessage(new AIUIMessage(AIUIConstant.CMD_STOP_RECORD, 0, 0, "data_type=audio,sample_rate=16000", null));
    }

    public void startRecordAudio() {
        sendMessage(new AIUIMessage(AIUIConstant.CMD_START_RECORD, 0, 0, "data_type=audio,sample_rate=16000", null));
    }


    private void sendMessage(final AIUIMessage message){
                if(mAIUIAgent != null) {
                    //确保AIUI处于唤醒状态
                    if(mCurrentState != AIUIConstant.STATE_WORKING ){
                        mAIUIAgent.sendMessage(new AIUIMessage(AIUIConstant.CMD_WAKEUP, 0, 0, "", null));
                    }

                    mAIUIAgent.sendMessage(message);
                }else {
                    showTip("AIUIAgent为空，请先创建");
                }
    }

    //文本语义
    public void writeText(String message){
        sendMessage(new AIUIMessage(AIUIConstant.CMD_WRITE, 0, 0,
                "data_type=text", message.getBytes()));
    }

    public void stopWriteText(){
        sendMessage(new AIUIMessage(AIUIConstant.CMD_STOP_WRITE, 0, 0, "data_type=text", null));

    }


    private AIUIListener mAIUIListener = new AIUIListener() {

        @Override
        public void onEvent(AIUIEvent event) {
            Log.i(TAG, "on event: " + event.eventType);

            switch (event.eventType) {
                case AIUIConstant.EVENT_CONNECTED_TO_SERVER:
                    Log.i(TAG, "onEvent: 已连接服务器");
                    break;

                case AIUIConstant.EVENT_SERVER_DISCONNECTED:
                    Log.i(TAG, "onEvent: 与服务器断连");
                    break;

                case AIUIConstant.EVENT_WAKEUP:
                    Log.i(TAG, "onEvent: 进入识别状态");
                    voiceAIListener.onListening();
                    break;

                case AIUIConstant.EVENT_RESULT:
                    processResult(event);
                    break;

                case AIUIConstant.EVENT_ERROR: {
                   showTip("错误: " + event.arg1 + "\n" + event.info);
                }
                break;

                case AIUIConstant.EVENT_VAD: {
                    if (AIUIConstant.VAD_BOS == event.arg1) {
                        Log.i(TAG, "onEvent: 找到vad_bos");
                    } else if (AIUIConstant.VAD_EOS == event.arg1) {
                        Log.i(TAG, "onEvent: 找到vad_eos");
                    } else {
                        Log.i(TAG, "onEvent:  " + event.arg2);
                    }
                }
                break;

                case AIUIConstant.EVENT_START_RECORD: {
                    voiceAIListener.onStartVoice();
                    Log.i(TAG, "onEvent: 已开始录音 ");
                }
                break;

                case AIUIConstant.EVENT_STOP_RECORD: {
                    voiceAIListener.onStopVoice();
                    Log.i(TAG, "onEvent: 已stop录音 ");
                }
                break;

                case AIUIConstant.EVENT_STATE: {    // 状态事件

                    mCurrentState = event.arg1;
                    if (AIUIConstant.STATE_IDLE == mCurrentState) {
                        // 闲置状态，AIUI未开启
                        Log.i(TAG, "onEvent: 闲置状态 ");
                    } else if (AIUIConstant.STATE_READY == mCurrentState) {
                        // AIUI已就绪，等待唤醒
                        Log.i(TAG, "onEvent: 等待唤醒 ");
                        voiceAIListener.onSleep();
                    } else if (AIUIConstant.STATE_WORKING == mCurrentState) {
                        // AIUI工作中，可进行交互
                        Log.i(TAG, "onEvent: 可进行交互 ");
                    }
                }
                break;

                case AIUIConstant.EVENT_CMD_RETURN: {
                    if (AIUIConstant.CMD_SYNC == event.arg1) {    // 数据同步的返回
                        int dtype = event.data.getInt("sync_dtype", -1);
                        int retCode = event.arg2;

                        switch (dtype) {
                            case AIUIConstant.SYNC_DATA_SCHEMA: {
                                if (AIUIConstant.SUCCESS == retCode) {
                                    // 上传成功，记录上传会话的sid，以用于查询数据打包状态
                                    // 注：上传成功并不表示数据打包成功，打包成功与否应以同步状态查询结果为准，数据只有打包成功后才能正常使用
                                   mSyncSid = event.data.getString("sid");

                                    // 获取上传调用时设置的自定义tag
                                    String tag = event.data.getString("tag");

                                    // 获取上传调用耗时，单位：ms
                                    long timeSpent = event.data.getLong("time_spent", -1);
                                    if (-1 != timeSpent) {
                                        Log.i(TAG, "onEvent: " + timeSpent + "ms");
                                    }

                                    showTip("上传成功，sid=" + mSyncSid + "，tag=" + tag + "，你可以试着说“打电话给刘德华”");
                                } else {
//                                    mSyncSid = "";
                                    showTip("上传失败，错误码：" + retCode);
                                }
                            }
                            break;
                        }
                    } else if (AIUIConstant.CMD_QUERY_SYNC_STATUS == event.arg1) {    // 数据同步状态查询的返回
                        // 获取同步类型
                        int syncType = event.data.getInt("sync_dtype", -1);
                        if (AIUIConstant.SYNC_DATA_QUERY == syncType) {
                            // 若是同步数据查询，则获取查询结果，结果中error字段为0则表示上传数据打包成功，否则为错误码
                            String result = event.data.getString("result");

//                            showTip(result);
                        }
                    }
                }
                break;

                default:
                    break;
            }
        }

    };



    private String getAIUIParams() {
        String params = "";

        AssetManager assetManager = MirrorApplication.getInstance().getResources().getAssets();
        try {
            InputStream ins = assetManager.open( "cfg/aiui_phone.cfg" );
            byte[] buffer = new byte[ins.available()];

            ins.read(buffer);
            ins.close();

            params = new String(buffer);

            JSONObject paramsJson = new JSONObject(params);

            params = paramsJson.toString();
        } catch (IOException | JSONException e) {
            e.printStackTrace();
        }

        return params;
    }


    /**
     * 处理语音结果（包含语音请求听写结果和智能响应结果）
     * @param event
     */
    private void processResult(AIUIEvent event) {
        try {
            JSONObject bizParamJson = new JSONObject(event.info);
            JSONObject data = bizParamJson.getJSONArray("data").getJSONObject(0);
            JSONObject params = data.getJSONObject("params");
            JSONObject content = data.getJSONArray("content").getJSONObject(0);

            if (content.has("cnt_id")) {
                String cnt_id = content.getString("cnt_id");
                JSONObject cntJson = new JSONObject(new String(event.data.getByteArray(cnt_id), "utf-8"));

                String sub = params.optString("sub");
                if ("nlp".equals(sub)) {
                    // 解析得到语义结果 response
                    JSONObject semanticResult = cntJson.optJSONObject("intent");
                    if (semanticResult != null && semanticResult.length() != 0) {
                        voiceAIListener.onResponse(semanticResult.toString(), messageHandler.getFormatMessage(semanticResult.toString()));
                    }
                } else if("iat".equals(sub)) {
                    //根据听写结果更新当前语音消息的内容
                    updateVoiceMessageFromIAT(cntJson);

                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    //处理听写PGS的队列 用户发出的
    private String[] mIATPGSStack = new String[256];
    private List<String> mInterResultStack = new ArrayList<>();
    private void updateVoiceMessageFromIAT(JSONObject cntJson) throws JSONException {

        JSONObject text = cntJson.optJSONObject("text");
        // 解析拼接此次听写结果
        StringBuilder iatText = new StringBuilder();
        JSONArray words = text.optJSONArray("ws");
        boolean lastResult = text.optBoolean("ls");
        for(int index = 0; index < words.length(); index++) {
            JSONArray charWord = words.optJSONObject(index).optJSONArray("cw");
            for(int cIndex = 0; cIndex < charWord.length(); cIndex++) {
                iatText.append(charWord.optJSONObject(cIndex).opt("w"));
            }
        }
        String voiceIAT;
        String pgsMode = text.optString("pgs");
        //非PGS模式结果
        if(TextUtils.isEmpty(pgsMode)) {
            if(TextUtils.isEmpty(iatText)) return;
            voiceAIListener.onRequestParsed(iatText.toString());
        } else {
            int serialNumber = text.optInt("sn");
            mIATPGSStack[serialNumber] = iatText.toString();
            //pgs结果两种模式rpl和apd模式（替换和追加模式）
            if("rpl".equals(pgsMode)) {
                //根据replace指定的range，清空stack中对应位置值
                JSONArray replaceRange = text.optJSONArray("rg");
                int start = replaceRange.getInt(0);
                int end = replaceRange.getInt(1);

                for(int index = start; index <= end; index++) {
                    mIATPGSStack[index] = null;
                }
            }

            StringBuilder PGSResult = new StringBuilder();
            //汇总stack经过操作后的剩余的有效结果信息
            for(int index = 0; index < mIATPGSStack.length; index++) {
                if(TextUtils.isEmpty(mIATPGSStack[index])) continue;

                if(!TextUtils.isEmpty(PGSResult.toString())) PGSResult.append("\n");
                PGSResult.append(mIATPGSStack[index]);
                //如果是最后一条听写结果，则清空stack便于下次使用
                if(lastResult) {
                    mIATPGSStack[index] = null;
                }
            }
            voiceIAT = join(mInterResultStack) + PGSResult.toString();
            voiceAIListener.onRequestParsed(voiceIAT);
            if(lastResult) {
                mInterResultStack.add(PGSResult.toString());
            }
        }
    }


    private OnVoiceAIListener voiceAIListener;


    public interface OnVoiceAIListener {
        void onEvent(AIUIEvent event);

        void onListening();

        void onSleep();

        void onStartVoice();

        void onStopVoice();

        void onRequestParsed(String sendText);

        void onResponse(String raw, String msg);
    }

    private void showTip(final String str) {
        Log.i(TAG, "showTip: "+str);
    }

    private String join(List<String> data) {
        StringBuilder builder = new StringBuilder();
        for(int index=0; index < data.size(); index++) {
            builder.append(data.get(index));
            builder.append("\n");
        }

        return builder.toString();
    }
}
